package de.ludo.dao;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import de.ludo.entities.Game;
import de.ludo.entities.Highscore;
import de.ludo.entities.LudoSession;
import de.ludo.entities.Player;
import de.ludo.entities.User;
import de.ludo.util.GameStatus;
import de.ludo.util.GameType;

@Stateless
public class DAO implements DAOLocal {

	@PersistenceContext
	EntityManager em;

	public Game findGameById(int gameId) {
		return em.find(Game.class, gameId);
	}

	public LudoSession findSessionById(int id) {
		return em.find(LudoSession.class, id);
	}

	public int createSession(String userName) {
		LudoSession newSession = new LudoSession(userName);
		em.persist(newSession);
		return newSession.getId();
	}

	public void closeSession(int id) {
		LudoSession oldSession = em.find(LudoSession.class, id);
		em.remove(oldSession);
	}

	public User findUserByName(String name) {
		return em.find(User.class, name);
	}

	@Override
	public ArrayList<Game> findGamesByStatus(GameStatus status) {
		Query q = em.createQuery("Select g from Game g where g.status = ?1")
				.setParameter(1, status);
		Collection results = q.getResultList();
		ArrayList<Game> games = new ArrayList<Game>();
		for (Iterator i = results.iterator(); i.hasNext();) {
			games.add((Game) i.next());
		}
		return games;
	}

	@Override
	public Player findPlayerById(int sessionId) {
		return em.find(Player.class, sessionId);
	}

	@Override
	/**
	 * 
	 * @param username
	 * @return Integer with SessionId or null
	 */
	public Integer findSessionIdByUserName(String name) {
		LudoSession session = findSessionByUserName(name);
		if (session != null) {
			return session.getId();
		}
		return null;
	}

	/**
	 * 
	 * @param username
	 * @return LudoSession or null
	 */
	public LudoSession findSessionByUserName(String username) {
		Query q = em.createQuery(
				"Select s from LudoSession s where s.userName = ?1")
				.setParameter(1, username);
		Collection results = q.getResultList();
		Iterator i = results.iterator();
		if (i.hasNext()) {
			return (LudoSession) i.next();
		}
		return null;
	}

	@Override
	public void saveUser(User user) {
		em.persist(user);
	}

	@Override
	public void saveGame(Game game) {
		em.persist(game);
	}

	@Override
	public void savePlayer(Player player) {
		em.persist(player);
	}

	@Override
	public void updatePlayer(Player player) {
		em.merge(player);
	}

	@Override
	public void updateGame(Game game) {
		em.merge(game);
	}

	@Override
	public void updateUser(User user) {
		em.merge(user);
	}

	@Override
	public void deletePlayer(int sessionId) {
		Player player = findPlayerById(sessionId);
		em.remove(player);
	}

	@Override
	public void closeGame(int gameId) {
		Game game = em.find(Game.class, gameId);
		em.remove(game);
	}

	@Override
	public ArrayList<Game> findAllGames() {
		Query q = em.createQuery("Select g from Game g");
		Collection results = q.getResultList();
		ArrayList<Game> games = new ArrayList<Game>();
		for (Iterator i = results.iterator(); i.hasNext();) {
			games.add((Game) i.next());
		}
		return games;
	}

	@Override
	public void closeAllGames(ArrayList<Game> game) {
		for (Game g : game) {
			em.remove(g);
		}
	}

	@Override
	public ArrayList<LudoSession> findAllLudoSessions() {
		Query q = em.createQuery("Select s from LudoSession s");
		Collection results = q.getResultList();
		ArrayList<LudoSession> ls = new ArrayList<LudoSession>();
		for (Iterator i = results.iterator(); i.hasNext();) {
			ls.add((LudoSession) i.next());
		}
		return ls;
	}

	@Override
	public void closeAllLudoSessions(ArrayList<LudoSession> ludoSessions) {
		for (LudoSession ls : ludoSessions) {
			em.remove(ls);
		}

	}

	@Override
	public Highscore findHighscoreById(int highscoreId) {
		return em.find(Highscore.class, highscoreId);

	}

	@Override
	public Highscore findHighscoreByGameAndName(GameType gT, String username) {
		Query q = em
				.createQuery(
						"Select h from Highscore h where h.username = ?1 and h.gameType = ?2")
				.setParameter(1, username).setParameter(2, gT);
		Collection results = q.getResultList();
		Iterator i = results.iterator();
		if (i.hasNext()) {
			return (Highscore) i.next();
		}
		return null;
	}

	@Override
	public void saveHighscore(Highscore high) {
		em.persist(high);
	}

	@Override
	public void updateHighscore(Highscore high) {
		em.merge(high);
	}

	@Override
	public ArrayList<Highscore> getHighscoreList(GameType gameType) {
		Query q = em
				.createQuery(
						"Select s from Highscore s where s.gameType = ?1 order by s.score desc")
				.setParameter(1, gameType);
		Collection results = q.getResultList();
		ArrayList<Highscore> highscoreList = new ArrayList<Highscore>();
		for (Iterator i = results.iterator(); i.hasNext();) {
			highscoreList.add((Highscore) i.next());
		}
		return highscoreList;
	}
}
